package com.vornitologist.widgetset.client;

import java.util.List;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel;
import com.vaadin.addon.touchkit.gwt.client.TouchKitOfflineApp;
import com.vaadin.addon.touchkit.gwt.client.VNavigationBar;
import com.vaadin.addon.touchkit.gwt.client.VNavigationView;
import com.vaadin.addon.touchkit.gwt.client.VNumberField;
import com.vaadin.addon.touchkit.gwt.client.VTouchKitApplicationConnection;
import com.vaadin.addon.touchkit.gwt.client.VVerticalComponentGroup;
import com.vaadin.terminal.gwt.client.ui.VButton;
import com.vaadin.terminal.gwt.client.ui.VView;
import com.vornitologist.widgetset.client.OfflineDataService.Observation;
import com.vornitologist.widgetset.client.OfflineDataService.Species;

/**
 * This is an example of overridden offline functionality in a TouchKit
 * application.
 * <p>
 * As you have realized, writing offline apps is rather odd solution for Vaadin,
 * which tries to simplify your development environment by letting you develop
 * in server side JVM where all great libraries exist and where you don't need
 * to consider things like networking at all. However, in some apps a limited
 * offline app might be handy and in some cases it might be a critical
 * requirement. This example can be used as a basis for creating a portion of
 * app to work in offline mode. Beware that stepping into this direction will
 * throw you deep into the "web development h€11", so consider keeping your
 * offline portions as small and simple as possible.
 * <p>
 * This demo offline mode lets users to fill observations also in offline mode.
 * When user returns to full featured online mode, it asks whether to
 * synchronize these observations to server.
 * <p>
 * How things work from technical POV?
 * <ul>
 * <li>TouchKit intelligently packages "static resources" so that browser caches
 * them more stronger than commonly. This webapp can be started from home screen
 * even without network connection.
 * <li>If TouchKit recognizes that there is no working connection to the server,
 * it opens the offline mode which is in this case defined in this class.
 * <li>VornitolgistOffline mode is built with GWT spices with some Vaadin and
 * TouchKit specific client side widgets and APIs. With them developer can write
 * the offline mode in Java, but note that the code is not run in a JVM so you
 * will have the usual GWT restrictions. Vornitogist shows a limited UI for
 * adding observations.
 * <li>Observations are temporary persisted to HTML5 local storage.
 * <li>The app can be closed, reopend and even the device can be rebooted.
 * Offline persisted observations remain in the memory of the device.
 * <li>When the application can return to full featured server backed mode, it
 * asks if user wishes to synchronize observations from local storage to the
 * server so that all other users van also see them.
 * </ul>
 */
public class VornitologistOfflineMode extends TouchKitOfflineApp implements
		RepeatingCommand {
	private VNumberField countBox;
	private ListBox speciesBox;
	private VButton addObservation;
	private Species selectedSpecies;
	private Integer count;

	private int localCount = -1;
	private Label currentlyStoredLabel;
	private VButton goOnlineButton;
	private Label networkStatus;
	private FlowPanel flowPanel;

	/**
	 * Instead of the basic "no connection" screen, Vornitologist uses
	 * overridden offline app that can be used to fill observation.
	 */
	@Override
	protected void buildDefaultContent() {
		createUi();
	}

	private void createUi() {
		/*
		 * OfflineDataService has async api that returns available species from
		 * a cached resources.
		 */
		OfflineDataService.getSpecies(new OfflineDataService.Callback() {
			public void setSpecies(final List<Species> birds) {
				doCreateUi(birds);
			}
		});
	}

	private void doCreateUi(final List<Species> birds) {

		// final ListBox listBox = new ListBox();
		// listBox.setHeight("25px");
		// listBox.getElement().getStyle().setMarginTop(10, Unit.PX);
		// listBox.getElement().getStyle().setMarginBottom(10, Unit.PX);
		// listBox.addItem("-- Select species --");
		// for (Species species : birds) {
		// listBox.addItem(species.getDisplayString(), species.getId());
		// }
		//
		// listBox.addChangeHandler(new ChangeHandler() {
		// public void onChange(ChangeEvent event) {
		// if (listBox.getSelectedIndex() == 0) {
		// selectedSpecies = null;
		// } else {
		// selectedSpecies = birds.get(listBox.getSelectedIndex() - 1);
		// countBox.setFocus(true);
		// }
		// updateFormState();
		// }
		// });
		// speciesBox = listBox;
		//
		// countBox = new VNumberField();
		// countBox.addKeyPressHandler(new KeyPressHandler() {
		// public void onKeyPress(KeyPressEvent event) {
		// Scheduler.get().scheduleDeferred(new ScheduledCommand() {
		// public void execute() {
		// String value = countBox.getValue();
		// String sanitetized = value.replaceAll("[^0-9]", "");
		// if (!sanitetized.equals(value)) {
		// countBox.setValue(sanitetized);
		// }
		// value = sanitetized;
		// try {
		// count = Integer.parseInt(value);
		// } catch (Exception e) {
		// count = null;
		// }
		// updateFormState();
		// }
		// });
		// }
		// });
		//
		// addObservation = new VButton();
		// addObservation.setText("Add");
		// addObservation.setEnabled(false);
		// addObservation.addClickHandler(new ClickHandler() {
		// public void onClick(ClickEvent event) {
		// Observation obs = new Observation();
		// obs.setSpecies(selectedSpecies);
		// obs.setCount(count);
		// OfflineDataService.localStoreObservation(obs);
		// localCount++;
		// updateLocalCount();
		// resetForm();
		// }
		//
		// });

		/*
		 * We'll mostly use TouchKit's client side components to build to UI and
		 * some of TouchKit's style names to build the offline UI. This way we
		 * can get similar look and feel with the rest of the application.
		 */
		VNavigationView navigationView = new VNavigationView();
		getPanel().add(navigationView);
		navigationView.setHeight("100%");
		VNavigationBar navigationBar = new VNavigationBar();
		navigationBar.setCaption("Hawaii esta offline");
		navigationView.setNavigationBar(navigationBar);

		/*
		 * FlowPanel is the simples GWT panel, pretty similar to CssLayout in
		 * Vaadin. We can use it with some Vaadin stylenames to get e.g.
		 * similarly themed margin widths.
		 */
		flowPanel = new FlowPanel();
		flowPanel
				.setStyleName("v-csslayout-margin-left v-csslayout-margin-right");

		Label label = new Label("Hawaii Offline Mode");
		label.setStyleName("v-label-grey-title");
		flowPanel.add(label);

		VVerticalComponentGroup p = new VVerticalComponentGroup();
		p.add(new HTML(
				"<p>Hawaii se encuentra en modo offline, al recuperar la coneccion se sinc los datos </p>"));

		flowPanel.add(p);

		// label = new Label("Add observations");
		// label.setStyleName("v-label-grey-title");
		// flowPanel.add(label);
		// p = new VVerticalComponentGroup();
		//
		// CaptionComponentFlexBox fb = new CaptionComponentFlexBox();
		// label = new Label("Select species:");
		// fb.add(label);
		// fb.add(speciesBox);
		//
		// p.add(fb);
		//
		// fb = new CaptionComponentFlexBox();
		// fb.add(new Label("Count:"));
		// fb.add(countBox);
		//
		// p.add(fb);
		// p.add(addObservation);
		//
		// flowPanel.add(p);
		//
		// label = new Label("Non-synchronized observations");
		// label.setStyleName("v-label-grey-title");
		// flowPanel.add(label);
		// p = new VVerticalComponentGroup();
		//
		// updateLocalCount();
		// p.add(currentlyStoredLabel);
		//
		// flowPanel.add(p);

		showRestartButton();

		navigationView.addContent(flowPanel);

		currentlyStoredLabel.getElement().getStyle().setPaddingTop(10, Unit.PX);
		currentlyStoredLabel.getElement().getStyle()
				.setPaddingBottom(10, Unit.PX);

	}

	private void resetForm() {
		speciesBox.setSelectedIndex(0);
		countBox.setText("");
		selectedSpecies = null;
		updateFormState();
	}

	protected void updateLocalCount() {
		if (localCount == -1) {
			localCount = OfflineDataService.getStoredObservations();
		}
		if (currentlyStoredLabel == null) {
			currentlyStoredLabel = new Label();
		}
		currentlyStoredLabel.setText("You have currently " + localCount
				+ " non synchronized observations in local storage.");
	}

	private void updateFormState() {
		boolean readyToAddObservation = true;

		if (selectedSpecies == null) {
			readyToAddObservation = false;
		} else {
			speciesBox.getElement().getStyle().setBackgroundColor("");
		}

		if (count == null) {
			readyToAddObservation = false;
		} else {
			countBox.getElement().getStyle().setBackgroundColor(null);
		}

		addObservation.setEnabled(readyToAddObservation);

	}

	private void goOnline() {

		super.deactivate();
	}

	private void showRestartButton() {

		Label label = new Label("Estado de la conexion");
		label.setStyleName("v-label-grey-title");
		flowPanel.add(label);
		VVerticalComponentGroup vVerticalComponentGroup = new VVerticalComponentGroup();
		vVerticalComponentGroup
				.addStyleName("v-touchkit-verticalcomponentgroup");
		Panel p = (Panel) vVerticalComponentGroup.getWidget();

		goOnlineButton = new VButton();
		goOnlineButton.setText("Ir a modo online");
		goOnlineButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				goOnline();
			}
		});

		goOnlineButton.setVisible(false);

		networkStatus = new Label();
		networkStatus.getElement().getStyle().setPaddingTop(10, Unit.PX);
		networkStatus.getElement().getStyle().setPaddingBottom(10, Unit.PX);

		Scheduler.get().scheduleFixedPeriod(this, 1000);

		p.add(networkStatus);
		p.add(goOnlineButton);

		flowPanel.add(vVerticalComponentGroup);
	}

	@Override
	public void onlineApplicationStarted() {
		final int storedObservations = OfflineDataService
				.getStoredObservations();
		if (storedObservations > 0) {
			Scheduler.get().scheduleDeferred(new ScheduledCommand() {

				public void execute() {
//					boolean confirm = Window
//							.confirm("You have "
//									+ storedObservations
//									+ " observations that are not synchronized with the server. Would you like to post them now?");
//					if (confirm) {
//						List<Observation> andResetLocallyStoredObservations = OfflineDataService
//								.getAndResetLocallyStoredObservations();
//
//						VTouchKitApplicationConnection ac = getApplicationConnection();
//						VView view = ac.getView();
//
//						String[] a = new String[andResetLocallyStoredObservations
//								.size()];
//						for (int i = 0; i < a.length; i++) {
//							a[i] = andResetLocallyStoredObservations.get(i)
//									.toString();
//						}
//						ac.updateVariable(ac.getPid(view),
//								"offlineObservations", a, true);
//						localCount = 0;
//						updateLocalCount();
					//}
				}
			});
		}
	}

	@Override
	public void deactivate() {
		
	}

	public boolean execute() {
		if (isActive()) {
			if (networkStatus != null) {
				if (VTouchKitApplicationConnection.isNetworkOnline()) {
					networkStatus.setText("Estado de red conectado");
					networkStatus.getElement().getStyle().setColor("green");
					goOnlineButton.setVisible(true);
				} else {
					networkStatus.setText("Estado de red desconectado");
					networkStatus.getElement().getStyle().setColor("");
					goOnlineButton.setVisible(false);
				}
			}
			return true;
		}
		return false;
	}
}
